# —*— coding = utf-8 -*-
# @Time :2021/11/3018:18
# @File :Multi-Paxos.py
# @Software: PyCharm
'''
////////////////////////////////////////////////////////////////////
//                          _ooOoo_                               //
//                         o8888888o                              //
//                         88" . "88                              //
//                         (| ^_^ |)                              //
//                         O\  =  /O                              //
//                      ____/`---'\____                           //
//                    .'  \\|     |//  `.                         //
//                   /  \\|||  :  |||//  \                        //
//                  /  _||||| -:- |||||-  \                       //
//                  |   | \\\  -  /// |   |                       //
//                  | \_|  ''\---/''  |   |                       //
//                  \  .-\__  `-`  ___/-. /                       //
//                ___`. .'  /--.--\  `. . ___                     //
//              ."" '<  `.___\_<|>_/___.'  >'"".                  //
//            | | :  `- \`.;`\ _ /`;.`/ - ` : | |                 //
//            \  \ `-.   \_ __\ /__ _/   .-` /  /                 //
//      ========`-.____`-.___\_____/___.-`____.-'========         //
//                           `=---='                              //
//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        //
//         佛祖保佑       永无BUG     永不修改                       //
////////////////////////////////////////////////////////////////////
'''
#导入库
import random
import sys
import time
import numpy

#ui显示库
import PySide2
import pymysql
from PySide2 import QtWidgets
from PySide2.QtUiTools import QUiLoader


class Client1:
    def __init__(self):
        super(Client1, self).__init__()  # 子类继承父类init方法
        self.ui = QUiLoader().load('服务器1.ui')  # 登录界面路径加载
        self.ui.pushButton.clicked.connect(self.reception)
        self.ui.pushButton.clicked.connect(Propser.pack_command)

    def reception(self):
        global message1
        message1 = self.ui.lineEdit.text()
        global action1
        action1 = self.ui.lineEdit_2.text()

    def handle(self, c):
        lj = pymysql.connect(host="localhost", user="root", passwd="z12j34y56", database="Paxos",
                             charset="utf8")  # 连接数据库

        # 时钟暂停时间
        time.sleep(c[3])

        if c[2] == '读':
            cursor = lj.cursor()  # 定义游标
            sql = "select * from data where data_list like '%{}%'".format(c[1])  # sql语句
            # print(sql)
            cursor.execute(sql)  # 执行sql语句
            data = cursor.fetchall()  # 得到其中一条数据
            # print(data)
            if data:  # 数据存在
                self.ui.tableWidget.setRowCount(0)  # 不设置限制
                self.ui.tableWidget.insertRow(0)
                for row, form in enumerate(data):  # 循环
                    for column, item in enumerate(form):  # 循环
                        # 将数据写入tableWidget
                        self.ui.tableWidget.setItem(row, column, PySide2.QtWidgets.QTableWidgetItem(str(item)))
                        column += 1
                    row_position = self.ui.tableWidget.rowCount()
                    self.ui.tableWidget.insertRow(row_position)

            lj.commit()  # 数据库操作完成
            QtWidgets.QMessageBox.information(self.ui, "提示", "读取成功",
                                              QtWidgets.QMessageBox.Yes)
        if c[2] == '写':
            cursor = lj.cursor()  # 定义游标
            sql = "insert into data(data_list) values('{}') ".format(c[1])  # sql语句

            cursor.execute(sql)  # 执行sql语句
            lj.commit()
            QtWidgets.QMessageBox.information(self.ui, "提示", "写入成功",
                                              QtWidgets.QMessageBox.Yes)

        if c[2] == '删':
            cursor = lj.cursor()  # 定义游标
            sql = "delete from data where data_list = '{0}' ".format(c[1])  # sql语句
            cursor.execute(sql)  # 执行sql语句
            lj.commit()
            QtWidgets.QMessageBox.information(self.ui, "提示", "删除成功",
                                              QtWidgets.QMessageBox.Yes)
        lj.close()

        # return message, action
class Client2:
    def __init__(self):
        super(Client2, self).__init__()  # 子类继承父类init方法
        self.ui = QUiLoader().load('服务器2.ui')  # 登录界面路径加载

        self.ui.pushButton.clicked.connect(self.reception)
        self.ui.pushButton.clicked.connect(Propser.pack_command)

    def reception(self):
        global message2
        message2 = self.ui.lineEdit.text()
        global action2
        action2 = self.ui.lineEdit_2.text()


    def handle(self,c):

        lj = pymysql.connect(host="localhost", user="root", passwd="z12j34y56", database="Paxos",
                             charset="utf8")  # 连接数据库

        # 时钟暂停时间
        time.sleep(c[3])

        if c[2] == '读':
            cursor = lj.cursor()  # 定义游标
            sql = "select * from data where data_list like '%{}%'".format(c[1])  # sql语句
            # print(sql)
            cursor.execute(sql)  # 执行sql语句
            data = cursor.fetchall()  # 得到其中一条数据
            # print(data)
            if data:  # 数据存在
                self.ui.tableWidget.setRowCount(0)  # 不设置限制
                self.ui.tableWidget.insertRow(0)
                for row, form in enumerate(data):  # 循环
                    for column, item in enumerate(form):  # 循环
                        # 将数据写入tableWidget
                        self.ui.tableWidget.setItem(row, column, PySide2.QtWidgets.QTableWidgetItem(str(item)))
                        column += 1
                    row_position = self.ui.tableWidget.rowCount()
                    self.ui.tableWidget.insertRow(row_position)

            lj.commit()  # 数据库操作完成
        if c[2] == '写':
            cursor = lj.cursor()  # 定义游标
            sql = "insert into data(data_list) values('{}') ".format(c[1])  # sql语句
            print(sql)
            cursor.execute(sql)  # 执行sql语句
            QtWidgets.QMessageBox.information(self.ui, "提示", "写入成功",
                                              QtWidgets.QMessageBox.Yes)
            lj.commit()

        if c[2] == '删':
            cursor = lj.cursor()  # 定义游标
            sql = "delete from data where data_list = '{0}' ".format(c[1])  # sql语句
            cursor.execute(sql)  # 执行sql语句
            QtWidgets.QMessageBox.information(self.ui, "提示", "删除成功",
                                              QtWidgets.QMessageBox.Yes)
            lj.commit()
        lj.close()




class Client3:
    def __init__(self):
        super(Client3, self).__init__()  # 子类继承父类init方法
        self.ui = QUiLoader().load('服务器3.ui')  # 登录界面路径加载

        self.ui.pushButton.clicked.connect(self.reception)
        self.ui.pushButton.clicked.connect(Propser.pack_command)

    def reception(self):
        global message3
        message3 = self.ui.lineEdit.text()
        global action3
        action3 = self.ui.lineEdit_2.text()

    def handle(self, c):

        lj = pymysql.connect(host="localhost", user="root", passwd="z12j34y56", database="Paxos",
                             charset="utf8")  # 连接数据库

        # 时钟暂停时间
        time.sleep(c[3])

        if c[2] == '读':
            cursor = lj.cursor()  # 定义游标
            sql = "select * from data where data_list like '%{}%'".format(c[1])  # sql语句
            # print(sql)
            cursor.execute(sql)  # 执行sql语句
            data = cursor.fetchall()  # 得到其中一条数据
            # print(data)
            if data:  # 数据存在
                self.ui.tableWidget.setRowCount(0)  # 不设置限制
                self.ui.tableWidget.insertRow(0)
                for row, form in enumerate(data):  # 循环
                    for column, item in enumerate(form):  # 循环
                        # 将数据写入tableWidget
                        self.ui.tableWidget.setItem(row, column, PySide2.QtWidgets.QTableWidgetItem(str(item)))
                        column += 1
                    row_position = self.ui.tableWidget.rowCount()
                    self.ui.tableWidget.insertRow(row_position)

            lj.commit()  # 数据库操作完成
        if c[2] == '写':
            cursor = lj.cursor()  # 定义游标
            sql = "insert into data(data_list) values('{}') ".format(c[1])  # sql语句
            print(sql)
            cursor.execute(sql)  # 执行sql语句
            QtWidgets.QMessageBox.information(self.ui, "提示", "写入成功",
                                              QtWidgets.QMessageBox.Yes)
            lj.commit()

        if c[2] == '删':
            cursor = lj.cursor()  # 定义游标
            sql = "delete from data where data_list = '{0}' ".format(c[1])  # sql语句
            cursor.execute(sql)  # 执行sql语句
            QtWidgets.QMessageBox.information(self.ui, "提示", "删除成功",
                                              QtWidgets.QMessageBox.Yes)
            lj.commit()
        lj.close()






class Propser:
    def __init__(self):
        super(Propser, self).__init__()  # 子类继承父类init方法
        self.pack_command()


    def pack_command(self):
        if 'message1' in globals().keys():
            if message1:
                t_sleep = random.randint(1, 10)
                # time.sleep(t_sleep)
                global c1
                c1 =(time.time(),message1,action1,t_sleep)
                print(c1)
                Accpetor().vote()

        if 'message2' in globals().keys():
            if message2:
                t_sleep = random.randint(1, 10)
                # time.sleep(t_sleep)
                global c2
                c2 = (time.time(), message2,action2, t_sleep)
                print(c2)
                Accpetor().vote()

        if 'message3' in globals().keys():
            if message3:
                t_sleep = random.randint(1, 10)
                # time.sleep(t_sleep)
                global c3
                c3 = (time.time(), message3,action3, t_sleep)
                Accpetor().vote()



class Accpetor:
    #选举leader，multi 和basic不同的便是multi是选举leader来保持一致性的，
    # 而basic则是直接向accpetor进行广播，对voter进行统计，超半数同意则成功

    def __init__(self):
        super(Accpetor, self).__init__()  # 子类继承父类init方法


    def voter1(self):
        #这里用随机数来模拟选举
        global r1
        r1 = random.randint(1, 5)

        if 'voter_num' in globals().keys():
            if voter_num == 1:
               #try:
               if 'c1' in globals().keys():
                   if c1:
                       Client1.handle(c1)
               if 'c2' in globals().keys():
                   if c2:
                       Client2.handle(c2)
               if 'c3' in globals().keys():
                   if c3:
                       Client3.handle(c3)



        return r1
    def voter2(self):
        # 这里用随机数来模拟选举
        global r2
        r2 = random.randint(1, 5)

        if 'voter_num' in globals().keys():
            if voter_num == 2:
                if 'c1' in globals().keys():
                    if c1:
                        Client1.handle(c1)
                if 'c2' in globals().keys():
                    if c2:
                        Client2.handle(c2)
                if 'c3' in globals().keys():
                    if c3:
                        Client3.handle(c3)

        return  r2
    def voter3(self):
        # 这里用随机数来模拟选举
        global r3
        r3 = random.randint(1, 5)
        if 'voter_num' in globals().keys():
            if voter_num == 3:
                if 'c1' in globals().keys():
                    if c1:
                        Client1.handle(c1)
                if 'c2' in globals().keys():
                    if c2:
                        Client2.handle(c2)
                if 'c3' in globals().keys():
                    if c3:
                        Client3.handle(c3)

        return r3
    def voter4(self):
        # 这里用随机数来模拟选举
        global r4
        r4 = random.randint(1, 5)
        if 'voter_num' in globals().keys():
            if voter_num == 4:
                if 'c1' in globals().keys():
                    if c1:
                        Client1.handle(c1)
                if 'c2' in globals().keys():
                    if c2:
                        Client2.handle(c2)
                if 'c3' in globals().keys():
                    if c3:
                        Client3.handle(c3)

        return r4
    def voter5(self):
        # 这里用随机数来模拟选举
        global r5
        r5 = random.randint(1, 5)
        if 'voter_num' in globals().keys():
            if voter_num == 5:
                if 'c1' in globals().keys():
                    if c1:
                        Client1.handle(c1)
                if 'c2' in globals().keys():
                    if c2:
                        Client2.handle(c2)
                if 'c3' in globals().keys():
                    if c3:
                        Client3.handle(c3)

        return r5


    def vote(self):
        if 'voter_num' not in globals().keys():
            self.voter1()
            self.voter2()
            self.voter3()
            self.voter4()
            self.voter5()
        all_voter = [r1,r2,r3,r4,r5]
        # print("all_voter",all_voter)
        bcount = numpy.bincount(all_voter)
        print("本次选举状况：",bcount)

        count = 0
        print("本次选举leader的人数：",bcount.max())
        for i in bcount:
            if  i  == bcount.max():
                count +=1

        print("leader数：",count)
        if count >= 2:
            self.voter1()
            self.voter2()
            self.voter3()
            self.voter4()
            self.voter5()
            self.vote()
        global voter_num
        if count < 2:
            for i in range(len(bcount)):
                if bcount[i] == bcount.max():
                    voter_num = i

                    Learner().execute()

                    print("master是：",voter_num)
        print("完成")






class Learner:

    def __init__(self):
        super(Learner, self).__init__()  # 子类继承父类init方法
        # self.accpetor = Accpetor()

    def execute(self):
        if voter_num == 1:
            Accpetor().voter1()
            if 'c1' in globals().keys():
                if c1:
                    f = open("log1.txt", "a")
                    f.write(str(c1))
                    f.close()
            if 'c2' in globals().keys():
                if c2:
                    f = open("log2.txt", "a")
                    f.write(str(c2))
                    f.close()
            if 'c3' in globals().keys():
                if c3:
                    f = open("log3.txt", "a")
                    f.write(str(c3))
                    f.close()
        if voter_num == 2:
            Accpetor().voter2()
            if 'c1' in globals().keys():
                if c1:
                    f = open("log1.txt", "a")
                    f.write(str(c1))
                    f.close()
            if 'c2' in globals().keys():
                if c2:
                    f = open("log2.txt", "a")
                    f.write(str(c2))
                    f.close()
            if 'c3' in globals().keys():
                if c3:
                    f = open("log3.txt", "a")
                    f.write(str(c3))
                    f.close()
        if voter_num == 3:
            Accpetor().voter3()
            if 'c1' in globals().keys():
                if c1:
                    f = open("log1.txt", "a")
                    f.write(str(c1))
                    f.close()
            if 'c2' in globals().keys():
                if c2:
                    f = open("log2.txt", "a")
                    f.write(str(c2))
                    f.close()
            if 'c3' in globals().keys():
                if c3:
                    f = open("log3.txt", "a")
                    f.write(str(c3))
                    f.close()
        if voter_num == 4:
            Accpetor().voter4()
            if 'c1' in globals().keys():
                if c1:
                    f = open("log1.txt", "a")
                    f.write(str(c1))
                    f.close()
            if 'c2' in globals().keys():
                if c2:
                    f = open("log2.txt", "a")
                    f.write(str(c2))
                    f.close()
            if 'c3' in globals().keys():
                if c3:
                    f = open("log3.txt", "a")
                    f.write(str(c3))
                    f.close()
        if voter_num == 5:
            Accpetor().voter5()
            if 'c1' in globals().keys():
                if c1:
                    f = open("log1.txt", "a")
                    f.write(str(c1))
                    f.close()
            if 'c2' in globals().keys():
                if c2:
                    f = open("log2.txt", "a")
                    f.write(str(c2))
                    f.close()
            if 'c3' in globals().keys():
                if c3:
                    f = open("log3.txt", "a")
                    f.write(str(c3))
                    f.close()


if __name__ == '__main__':#任务执行
    app = QtWidgets.QApplication(sys.argv)#实例化一个应用对象（打开一个类似于窗口的东西）
    Client1 = Client1()  # 令wm = 服务器界面
    Client1.ui.show()  # 展示登录界面

    Client2 = Client2()  # 令wm = 登录函数
    Client2.ui.show()  # 展示登录界面

    Client3 = Client3()  # 令wm = 登录函数
    Client3.ui.show()  # 展示登录界面

    sys.exit(app.exec_())  # 程